package com.runa.monitor.platinterface.netservice.equipment;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.*;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.persistence.task.TaskTypeEnum;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorResponseData;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import com.runa.rccprotocol.dto.runa.RunaDeviceRequestData;
import com.runa.rccprotocol.dto.tiangang.TianGangValveRequestData;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * @author diandian
 * @Date 2021/11/1 14:37
 */
@Slf4j
public class TianGangDriver extends NetEqu<String> {
    Logger logger = LoggerFactory.getLogger(getClass());

    private String electricSerial;
    private String netEquModel;

    private static byte[] tianGangFunctionCode = new byte[]{0x1f, (byte) 0x90};
    private static byte[] tianGangFactoryCode = new byte[]{0, 0x11, 0x11};
    private static byte[] wanHuaFunctionCode = new byte[]{(byte) 0xC3, 0x52};
    private static byte[] wanHuaFactoryCode = new byte[]{0x01, 0, 0};
    private static byte equCode = 0x20;

    public TianGangDriver(String serial, Integer timeout, String electricSerial, String netEquModel) {
        super(serial, timeout);
        this.electricSerial = electricSerial;
        this.netEquModel = netEquModel;
        this.maxRetry = 2;
    }


    @Override
    public void readNodeEqu(List<Node> nodeList, TaskFunction function, EquData.EquDataType type) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, nodeList);
            return;
        }
//        List<Node> nodes = filterNodes(nodeSerial, function, type);
        switch (type) {
            case METER:
                readHouseMeter(nodeList, function);
                break;
            case VALVE:
                readHouseValve(nodeList, function);
                break;
            case PUBLIC_UNIT:
                readBuilderValve(nodeList, function);
                break;
            case TEMPERATURE_PANEL:
                break;
            default:
        }
    }

    private void readBuilderValve(List<Node> nodeList, TaskFunction function) {
        for (Node node : nodeList) {
            if ("R3".equalsIgnoreCase(node.getModel())) {
                RunaDeviceRequestData requestData = new RunaDeviceRequestData(serial());
                requestData.readBuildValve(node.getIndex());
                log.debug("读R3楼阀: {} {} {}", serial(), node.getSerial(), ByteUtil.byteToHexString(requestData.getData()));
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function);
            } else {
                log.error("{}: 阀 {} 型号协议未开发", serial(), node.getSerial());
            }
        }
    }

    private final ExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    private void readHouseMeter(List<Node> meters, TaskFunction function) {
//        log.debug("天罡集中器进入抄表"+ JSON.toJSONString(meters)+"---"+priority);
        for (Node node : meters) {
            this.currNode = node;
            TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
            if ("RC74-2".equalsIgnoreCase(node.getModel()) || "CR62-MR".equals(netEquModel)) {
                //天罡站表
                RunaDeviceRequestData runaDeviceRequestData = new RunaDeviceRequestData(serial());
                runaDeviceRequestData.readHeatMeter(node.getSerial(), equCode, tianGangFactoryCode, tianGangFunctionCode);
                runaDeviceRequestData.setRemain(Collections.singletonList(node));
                sendRequest(runaDeviceRequestData, function);
            } else if ("URT-R1".equalsIgnoreCase(node.getModel())) {
                //测试 todo  这是楼表 海威茨楼表
                requestData.readHeatMeterOf188(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function);
            }else if("URT-R2".equalsIgnoreCase(node.getModel())){
                //序号代表短址
                requestData.readHeatMeterOfModbus(node.getIndex());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function);
            } else if ("MTH-6".equalsIgnoreCase(node.getModel())) {
                // 南京迈拓 天罡集中器透传
                requestData.readMetterMeter(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                logger.debug("南京迈拓: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
                sendRequest(requestData, function);
            } else if ("蒙制".equalsIgnoreCase(node.getModel())) {
                // 华蒙 天罡集中器透传
                requestData.readHmMeter(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                logger.debug("华蒙: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
                sendRequest(requestData, function);
            }
            else if ("773".equals(node.getModel())) {
                executor.execute(() -> {
                    RccTaskFunction.SyncFunction syncFunction = new RccTaskFunction.SyncFunction(null, function.getPriority());
                    requestData.selectDaiAoMeter(node.getSerial());
                    requestData.setRemain(Collections.singletonList(node));
                    LogUtil.info(serial(), "选择表: {}", node.getSerial());
                    sendRequest(requestData, syncFunction);
                    if (syncFunction.waitResult()) {
                        TianGangValveRequestData readRequest = new TianGangValveRequestData(serial());
                        readRequest.readDaiAoMeter(node.getSerial());
                        readRequest.setRemain(Collections.singletonList(node));
                        syncFunction = new RccTaskFunction.SyncFunction(function, timeout(), function.getPriority());
                        LogUtil.info(serial(), "抄表: {}", node.getSerial());
                        sendRequest(readRequest, syncFunction, TaskTypeEnum.READ_DA_METER);
                        syncFunction.waitResult();
                    }
                });
            }
//            else if ("2U".equals(node.getModel())) {
//
//            }
            else {
                executor.execute(() -> {
                    RccTaskFunction.SyncFunction syncFunction = new RccTaskFunction.SyncFunction(null, function.getPriority());
                    requestData.chooseHouseMeter(node.getSerial());
                    requestData.setRemain(Collections.singletonList(node));
                    sendRequest(requestData, syncFunction);

                    if (syncFunction.waitResult()) {
                        TianGangValveRequestData readRequest = new TianGangValveRequestData(serial());
                        readRequest.readHouseter();
                        readRequest.setRemain(Collections.singletonList(node));
                        syncFunction = new RccTaskFunction.SyncFunction(function, timeout(), function.getPriority());
                        sendRequest(readRequest, syncFunction);
                        if (syncFunction.waitResult()) {
                            requestData.destroy();
                            syncFunction = new RccTaskFunction.SyncFunction(null, timeout(), function.getPriority());
                            sendRequest(requestData, syncFunction);
                            syncFunction.waitResult();
                        }
                    }
                });
//                //天罡楼表RC74
//                log.debug("天罡集中器进入抄表");//todo  这里连续三个指令的可以后期可以不等待，直接进去三个
//                Boolean initRes = initAndChooseHouseMeter(requestData, node.getSerial());
//                log.debug("天罡集中器进入抄表initRes"+initRes);
//                if (initRes) {
//                    requestData.readHouseter();
//                    requestData.setRemain(Collections.singletonList(node));
//                    sendRequest(requestData, function);
//                    destroy(requestData, function.getPriority()-1);
//                }
            }
        }
    }

    private void readHouseValve(List<Node> valves, TaskFunction function) {
        for (Node node : valves) {
            this.currNode = node;
            if ("TF-LM-V".equalsIgnoreCase(node.getModel())) {
                TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                requestData.readWkxValve(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function);
                logger.debug("五颗星抄阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
            } else if ("RU-VC-03".equals(node.getModel())) {
                RunaDeviceRequestData runaDeviceRequestData = new RunaDeviceRequestData();
                runaDeviceRequestData.readHouseValve(node.getSerial());
                runaDeviceRequestData.setRemain(Collections.singletonList(node));
                sendRequest(runaDeviceRequestData, function);
                logger.debug("瑞纳抄阀: {} {}", serial(), ByteUtil.byteToHexString(runaDeviceRequestData.getData()));
            } else if ("ZF-Y".equals(node.getModel())) {
                TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                requestData.readKtValve(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function, TaskTypeEnum.READ_KT_VALVE);
                logger.debug("酷特抄阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
            } else if ("DDF3-12133".equals(node.getModel())) {
                TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                requestData.readPsValve(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function, TaskTypeEnum.READ_PS_VALVE);
            } else if ("TBL25-2MT".equals(node.getModel())) {
                TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                requestData.readTigerValve(node.getSerial());
                requestData.setRemain(Collections.singletonList(node));
                sendRequest(requestData, function, TaskTypeEnum.READ_TIGER_VALVE);
            } else {
                TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                Boolean initRes = initAndChoose(requestData, node.getSerial());
                if (initRes) {
                    requestData.readHouseValve();
                    requestData.setRemain(Collections.singletonList(node));
                    sendRequest(requestData, function);
                    destroy(requestData, function.getPriority()-1);
                }

            }
        }
    }



    public void readElectric(TaskFunction function) {
        TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
        requestData.readElectric(electricSerial);
        sendRequest(requestData, function);
    }

    private Boolean initAndChooseHouseMeter(TianGangValveRequestData requestData, String serial) {
        RccTaskFunction.SyncFunction chooseFunc = new RccTaskFunction.SyncFunction(0);
        requestData.chooseHouseMeter(serial);
        log.debug("天罡集中器进入抄表requestData"+JSON.toJSONString(requestData));
        sendRequest(requestData, chooseFunc);
        return chooseFunc.waitResult();
    }

    private Boolean initAndChoose(TianGangValveRequestData requestData, String serial) {
        RccTaskFunction.SyncFunction chooseFunc = new RccTaskFunction.SyncFunction(0);
        requestData.chooseHouseValve(serial);
        sendRequest(requestData, chooseFunc);
        return chooseFunc.waitResult();
    }

    private void destroy(TianGangValveRequestData requestData, int priority) {
        RccTaskFunction.SyncFunction closeFunc = new RccTaskFunction.SyncFunction(priority);
        requestData.destroy();
        sendRequest(requestData, closeFunc);
        closeFunc.waitResult();
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {

    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {

    }

    @Override
    public void valveOnOffControl(List<Node> valves, boolean ifLock, Integer opening, TaskFunction function) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, valves);
            return;
        }
        for (Node valve : valves) {
            if (valve != null) {
                if ("TF-LM-V".equalsIgnoreCase(valve.getModel())) {
                    TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                    requestData.setWkxValveOpen(valve.getSerial(), opening, ifLock);
                    requestData.setRemain(valve);
                    sendRequest(requestData, function);
                    logger.debug("五颗星控阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
                } else if ("ZF-Y".equals(valve.getModel())) {
                    TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                    requestData.setKtValveOpen(valve.getSerial(), opening, ifLock);
                    requestData.setRemain(valve);
                    sendRequest(requestData, function);
                    logger.debug("酷特控阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
                } else if ("DDF3-12133".equals(valve.getModel())) {
                    // 普赛
                    executor.execute(() -> {
                        LogUtil.info(serial(), "普赛阀控: {} {}", opening, ifLock);
                        if (opening == 0) {
                            TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                            requestData.setPsValveOpen(valve.getSerial(), opening, ifLock);
                            requestData.setRemain(valve);
                            sendRequest(requestData, function, TaskTypeEnum.WRITE_PS_VALVE);
                        } else {
                            RccTaskFunction.SyncFunction syncFunction = new RccTaskFunction.SyncFunction(null, function.getPriority());
                            TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                            requestData.setPsValveMaxOpen(valve.getSerial(), opening);
                            requestData.setRemain(valve);
                            sendRequest(requestData, syncFunction, TaskTypeEnum.WRITE_PS_VALVE);
                            if (syncFunction.waitResult()) {
                                requestData = new TianGangValveRequestData(serial());
                                requestData.setPsValveOpen(valve.getSerial(), opening, ifLock);
                                requestData.setRemain(valve);

                                syncFunction = new RccTaskFunction.SyncFunction(function, timeout(), function.getPriority());
                                sendRequest(requestData, syncFunction, TaskTypeEnum.WRITE_PS_VALVE);
                                syncFunction.waitResult();
                            }
                        }

                    });

                } else if ("RU-VC-03".equals(valve.getModel())) {
                    RunaDeviceRequestData requestData = new RunaDeviceRequestData(serial());
                    requestData.setHouseValveOpen(valve.getSerial(), opening, ifLock);
                    requestData.setRemain(valve);
                    sendRequest(requestData, function);
                    logger.debug("瑞纳控阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
                } else {
                    TianGangValveRequestData requestData = new TianGangValveRequestData(serial());
                    Boolean initRes = initAndChoose(requestData, valve.getSerial());
                    if (initRes) {
                        requestData.setHouseValveOpen(opening);
                        requestData.setRemain(valve);
                        sendRequest(requestData, function);
                        destroy(requestData, function.getPriority()-1);
                    }
                }
            }
        }
    }

    @Override
    public void receive(ConcentratorResponseData responseData) {
        super.receive(responseData);
    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> valves, Integer model, Map param, TaskFunction function) {
        RunaDeviceRequestData requestData;
        for (Node unit : valves) {
            if (unit != null) {
                switch (model) {
                    case 1:
                        requestData = new RunaDeviceRequestData();
                        requestData.setBuildValveOpen(unit.getIndex(), (int) Float.parseFloat(param.get("targetValue").toString()));
                        requestData.setRemain(unit);
                        sendRequest(requestData, function);
                        break;
                    case 2:
                        break;
                    case 3:
                        break;
                    case 4:
                        Map<String, Integer> valveUpDown = (Map<String, Integer>) param.get("valveUpDown");
                        requestData = new RunaDeviceRequestData();
                        requestData.setBuildValveLimit(unit.getIndex(), valveUpDown.get("valveUp"), valveUpDown.get("valveDown"));
                        requestData.setRemain(unit);
                        sendRequest(requestData, function);
                        break;
                    default:
                }
            }
        }
    }

    @Override
    public void sentPublicUnitModel(List<Node> valveSerial, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valveSerial, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valveSerial, Node meterSerial, TaskFunction function) {

    }

    @Override
    public void heartbeatUpdate() {

    }

    @Override
    public boolean heartStop() {
        return false;
    }

    public static void main(String[] args) {
        TianGangValveRequestData requestData = new TianGangValveRequestData("11112222");
        requestData.chooseHouseMeter("11112222");
        byte[] data = requestData.getData();
        String s = ByteUtil.byteToHexString(data, 0, data.length);
        System.out.println(s);

        final Queue<Integer> requestQueue = new PriorityBlockingQueue<>();
        requestQueue.offer(4);
        requestQueue.offer(3);
        requestQueue.offer(2);
        requestQueue.offer(1);
        while (!requestQueue.isEmpty()) {
            System.out.println(requestQueue.poll());
        }


    }
}
